//Simple code to compile and link GLSL code in an OpenGL program.

//Dr. Orion Lawlor, olawlor@acm.org, 2009-01-04 (Public Domain)
//This version includes enhancements by Dr. Glenn Chappell.
#include "stdafx.h"
#include "glsl.h"

namespace OrionFlames
{
//Output given string to cout, followed by newline, then wait for
//keypress, and do exit(1).
static void errorExit(const std::string & msg)
{
	std::cout << msg << std::endl << std::endl;
	std::cout << "Press ENTER to quit ";
	while (std::cin.get() != '\n');
	std::exit(1);
}

//Print message and exit if GLSL build error.
inline void checkShaderOp(GLhandleARB obj,
						  GLenum errType,
						  const std::string& location) 
{
	GLint compiled;
	glGetObjectParameterivARB(obj, errType, &compiled);

	if (!compiled)
	{
		GLsizei len = 0;
		const int logSize = 10000;
		GLcharARB errorLog[logSize];

		//Our buffer (errorLog) must be fixed-length, because we are using
		//OpenGL's "C" API. However, OpenGL knows how big the buffer is,
		//and there is no possibility of overflow.
		glGetInfoLogARB(obj, GLsizei(logSize), &len, errorLog);
		errorExit("ERROR - Could not build GLSL shader: " + location + "\n\nERROR LOG:\n" + errorLog);
	}
}

//Create a vertex or fragment shader from this code.
static GLhandleARB makeShaderObject(int target, const char* code)
{
	GLhandleARB h = glCreateShaderObjectARB(target);
	glShaderSourceARB(h, 1, &code, NULL);
	glCompileShaderARB(h);
	checkShaderOp(h, GL_OBJECT_COMPILE_STATUS_ARB, code);
	return h;
}

//Create a complete shader object from these chunks of GLSL shader code.
//You still need to glUseProgramObjectARB(return value).
GLhandleARB makeProgramObject(const char *vertex, const char *fragment)
{
	if (glUseProgramObjectARB == 0) 
	{
		//glew never set up, or OpenGL is too old.
		std::cout << "Error!  OpenGL hardware or software too old--no GLSL!\n";
		return 0;
	}

	GLhandleARB p = glCreateProgramObjectARB();
	GLhandleARB vo = makeShaderObject(GL_VERTEX_SHADER_ARB, vertex);
	GLhandleARB fo = makeShaderObject(GL_FRAGMENT_SHADER_ARB, fragment);
	glAttachObjectARB(p, vo);
	glAttachObjectARB(p, fo);
	glLinkProgramARB(p);
	checkShaderOp(p, GL_OBJECT_LINK_STATUS_ARB, "linking vertex shader " + std::string(vertex) + " and fragment shader " + std::string(fragment));
	glDeleteObjectARB(vo);
	glDeleteObjectARB(fo);
	return p;
}
}